/**
 * Copyright (C) 2010 Comba Telecom Systems Holdings Ltd. All rights reserved
 *
 * �������Ȩ�龩��ͨ��ϵͳ�ع����޹�˾���У����ܵ���صķ��ɱ�����
 * û�о����Ȩ�����ߵ�����ͬ�⣬
 * �κ�������˻���֯������κ���ʽ�����ļ����ļ��Ĳ��ִ�������������ҵ��;��
 *
 */
package com.xing.dao;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.sql.DataSource;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.CallableStatementCallback;
import org.springframework.jdbc.core.CallableStatementCreator;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.stereotype.Repository;

import com.xing.util.Util;

/**
 * �����ڴ�д�ϴ��๦���������֡�
 * 
 * @version
 * @author wushen 2011-7-4 ����03:47:32
 * 
 */
@Repository("baseDao")
public class BaseDaoImpl implements BaseDao {

	private static Logger logger = Logger.getLogger(BaseDaoImpl.class);

	@Resource
	private SessionFactory sessionFactory;
	@Resource
	private DataSource dataSource;

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}
	
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
	public HibernateTemplate getHibernateTemplate() {
		HibernateTemplate hibernateTemplate = new HibernateTemplate(
				sessionFactory);
		return hibernateTemplate;
	}

	public JdbcTemplate getJdbcTemplate() {
		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
		return jdbcTemplate;
	}

	/**
	 * �����ڴ������������֡�
	 * 
	 * (non-Javadoc)
	 * 
	 * @see com.comba.omc.collect.analyses.helper.AnalysesDao#getList(java.lang.String)
	 */
	@Override
	public List<?> getList(String hql) {
		String fetchParam = "";
		String orderBy = "";
		List<ParamModel> paramModelList = null;
		return getList(fetchParam, hql, orderBy, paramModelList);
	}
	
	@Override
	public Map<String, Object> getListAndCount(String fetchParam, String hql,
			String orderBy, Integer page, Integer pageRow) {
		List<ParamModel> paramModelList = null;
		return getListAndCount(fetchParam, hql, orderBy, paramModelList, page, pageRow);
	}
	
	@Override
	public List<?> getList(final String fetchParam, final String hql,
			final String orderBy, final List<ParamModel> paramModelList) {
		return listQuery(fetchParam, hql, orderBy, paramModelList, null, null);
	}
	
	@Override
	public Map<String, Object> getListAndCount(String fetchParam, String hql,
			String orderBy, List<ParamModel> paramModelList, Integer page, Integer pageRow) {
		
		List<?> countList = getList("select count(*) as count " + hql);
		int count = Integer.parseInt(countList.get(0).toString());
		
		List<?> rowList =listQuery(fetchParam, hql, orderBy, paramModelList, page, pageRow);
		
		Map<String, Object> result = new HashMap<String, Object>();
		result.put("total", count);
		result.put("rows", rowList);

		return result;
	}

	private List<?> listQuery(final String fetchParam, final String hql,
			final String orderBy, final List<ParamModel> paramModelList, final Integer page, final Integer pageRow) {

		HibernateTemplate hibernateTemplate = getHibernateTemplate();

		List<?> list = new ArrayList<Object>();

		StringBuilder sb = new StringBuilder();
		sb.append(fetchParam);
		sb.append(hql);
		sb.append(orderBy);
		String qs = sb.toString();
		if (Util.isEmpty(qs)) {
			logger.info(" could not execute null query! ");
			return list;
		}

		list = (List<?>) hibernateTemplate.execute(new HibernateCallback() {

			public Object doInHibernate(Session session) {

				Query q = session.createQuery(fetchParam + hql + orderBy);
				if (pageRow != null) {
					q.setMaxResults(pageRow);
				}
				if (page != null) {
					q.setFirstResult((page - 1) * pageRow);
				}
				// ��ֵ
				if (!Util.isEmpty(paramModelList)) {
					for (ParamModel tp : paramModelList) {
						q = tp.setParam(q);// �Բ�����д���
					}
				}
				return q.list();
			}
		});

		return list;

	}

	/**
	 * �����ڴ������������֡�
	 * 
	 * (non-Javadoc)
	 * @see com.comba.omc.collect.analyses.helper.AnalysesDao#getListByNameQuery(java.lang.String, java.util.List)
	 */
	@Override
	public List<?> getListByNameQuery(final String queryName,
			final List<ParamModel> paramModelList) {
		
		HibernateTemplate hibernateTemplate = getHibernateTemplate();

		return (List<?>) hibernateTemplate.execute(new HibernateCallback() {

			public Object doInHibernate(Session session) {

				Query q = session.getNamedQuery(queryName);
				// ��ֵ
				if (!Util.isEmpty(paramModelList)) {
					for (ParamModel tp : paramModelList) {
						q = tp.setParam(q);// �Բ�����д���
					}
				}
				return q.list();
			}
		});

	}
		
	/**
	 * �����ڴ������������֡�
	 * 
	 * (non-Javadoc)
	 * @see com.comba.omc.collect.analyses.helper.AnalysesDao#executeByNameQuery(java.lang.String, java.util.List)
	 */
	@Override
	public int executeByNameQuery(final String queryName,
			final List<ParamModel> paramModelList) {
		
		HibernateTemplate hibernateTemplate = getHibernateTemplate();

		return (Integer) hibernateTemplate.execute(new HibernateCallback() {

			public Object doInHibernate(Session session) {

				Query q = session.getNamedQuery(queryName);
				// ��ֵ
				if (!Util.isEmpty(paramModelList)) {
					for (ParamModel tp : paramModelList) {
						q = tp.setParam(q);// �Բ�����д���
					}
				}
				return q.executeUpdate();
			}
		});

	}


	/**
	 * �����ڴ������������֡�
	 * 
	 * (non-Javadoc)
	 * @see com.comba.omc.collect.analyses.helper.AnalysesDao#getDataByCriteria(java.lang.Class, java.util.List, java.util.List, java.util.List)
	 */
	@Override
	public List<?> getDataByCriteria(final Class<?> clazz,
			final List<Criterion> criList, final List<Order> ordList,
			final List<Projection> proList) {
		
		HibernateTemplate hibernateTemplate = getHibernateTemplate();

		return (List<?>) hibernateTemplate.execute(new HibernateCallback() {

			public Object doInHibernate(Session session) {

				Criteria cri = session.createCriteria(clazz);

				if (!Util.isEmpty(proList)) {
					for (Projection p : proList) {
						cri.setProjection(p);
					}
				}
				
				if (!Util.isEmpty(criList)) {
					for (Criterion criterion : criList) {
						cri.add(criterion);
					}
				}
				
				if (!Util.isEmpty(ordList)) {
					for (Order order : ordList) {
						cri.addOrder(order);
					}
				}

				return cri.list();
			}
		});

	}

	/**
	 * �����ڴ������������֡�
	 * 
	 * (non-Javadoc)
	 * @see com.comba.omc.collect.analyses.helper.AnalysesDao#callProcedureWithoutResult(java.lang.String, java.util.List, java.util.List)
	 */
	@Override
	public void callProcedureWithoutResult(final String sql, final List<Integer> typesList,
			final List<Object> paramList, final boolean autoCommit) {
		
		JdbcTemplate jdbcTemplate = getJdbcTemplate();
		
		jdbcTemplate.execute(
				new CallableStatementCreator() {

					@Override
					public CallableStatement createCallableStatement(
							Connection conn) throws SQLException {
						
						conn.setAutoCommit(autoCommit);
						return conn.prepareCall(sql);
					}
					
				}, 
				new CallableStatementCallback() {

					@Override
					public Object doInCallableStatement(CallableStatement cs)
							throws SQLException, DataAccessException {
						
						if (typesList != null && paramList != null) {
							if (typesList.size() != paramList.size()) {
								throw new SQLException("param type list size not equal param list size, check you call function!");
							}
						}
						
						if (!Util.isEmpty(typesList) 
								&& !Util.isEmpty(paramList)) {
							for (int i = 0; i < typesList.size(); i++) {
								cs.setObject(i+1, paramList.get(i), typesList.get(i));
							}							
						}
						
						cs.execute();
						
						return null;
					}
					
				}
			);
		
	}

	/**
	 * �����ڴ������������֡�
	 * 
	 * (non-Javadoc)
	 * @see com.comba.omc.collect.analyses.helper.AnalysesDao#getListBySql(java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public List<Object[]> getListBySql(String sql, Object[] args, int[] argTypes) {
		
		JdbcTemplate jdbcTemplate = getJdbcTemplate();
		
		if (args == null || argTypes == null) {
			args = new Object[0];
			argTypes = new int[0];
		}		
		
		return (List<Object[]>) jdbcTemplate.query(sql, args, argTypes, 
				new RowMapper() {

					@Override
					public Object mapRow(ResultSet rs, int rowNum)
							throws SQLException {						
						
						ResultSetMetaData rsmd = rs.getMetaData();
						int columnCount = rsmd.getColumnCount();
						Object[] objs = new Object[columnCount];
						
						for (int i = 0; i < columnCount; i++) {
							objs[i] = rs.getObject(i + 1);
						}
						
						return objs;
					}
			
		});
		
	}

	/**
	 * �����ڴ������������֡�
	 * 
	 * (non-Javadoc)
	 * @see com.comba.omc.collect.analyses.helper.AnalysesDao#saveList(java.util.List)
	 */
	@Override
	public void saveList(final List<?> list) {
		
		HibernateTemplate hibernateTemplate = getHibernateTemplate();
		
		hibernateTemplate.execute(new HibernateCallback() {

			@Override
			public Object doInHibernate(Session session)
					throws HibernateException, SQLException {
				
				int count = 0;
				for (Object obj : list) {
					
					session.save(obj);
					count++;
					
					if (count % 50 == 0) {
						session.flush();
						session.clear();
					}					
				}				
				
				return null;
			}
			
		});
		
	}

	/**
	 * �����ڴ������������֡�
	 * 
	 * (non-Javadoc)
	 * @see com.comba.omc.collect.analyses.helper.AnalysesDao#updateByHql(java.lang.String)
	 */
	@Override
	public int updateByHql(String hql) {
		return updateByHql(hql, null);
	}

	/**
	 * �����ڴ������������֡�
	 * 
	 * (non-Javadoc)
	 * @see com.comba.omc.collect.analyses.helper.AnalysesDao#updateByHql(java.lang.String, java.util.List)
	 */
	@Override
	public int updateByHql(final String hql, final List<ParamModel> paramModelList) {
		HibernateTemplate hibernateTemplate = getHibernateTemplate();

		return (Integer) hibernateTemplate.execute(new HibernateCallback() {

			public Object doInHibernate(Session session) {

				Query q = session.createQuery(hql);
				// ��ֵ
				if (!Util.isEmpty(paramModelList)) {
					for (ParamModel tp : paramModelList) {
						q = tp.setParam(q);// �Բ�����д���
					}
				}
				return q.executeUpdate();
			}
		});
	}

	

	
}
